#-*- coding:utf-8 -*-
from init_datas import *
from VNet import *

def IS_DOUBLE_ZERO(x):
    if abs(x) < 1e-4:
        return True
    return False

def vnet_print_test(vnet,save_dir = None):
    # 打印节点数据
    # vnet.print_node_datas(save_dir)
    # 打印分支数据
    vnet.print_edge_datas(save_dir)
    vnet.print_struct_datas(save_dir)
    # 打印压差数据
    vnet.print_delta_h_datas(save_dir)
    vnet.print_delta_q_datas(save_dir)
    # vnet.print_sensor_datas()
    # # 打印风机数据
    # vnet.print_fan_datas()
    # # 访问第一台风机所在分支的id
    # print('风机[%s]所在的分支id为:%s'%(vnet.fan_set[0]['id'],vnet.fan_set[0]['e_id']))
    # # 访问第一台风机的拟合参数
    # print('风机[%s]的特性曲线方程的参数为:[a0:%.2lf,a1:%.2lf,a2:%.2lf]'%
    # (vnet.fan_set[0]['id'],vnet.fan_set[0]['a0'],vnet.fan_set[0]['a1'],vnet.fan_set[0]['a2']))
    # # 访问分支e5的始末节点及风量
    # for eds in vnet.edge_set:
    #     if eds['id'] == '5':
    #         print('分支e%s的始末节点id(%s->%s),风量为:%.2lf'%(eds['id'],eds['s'],eds['t'],eds['q'],))

# 构造一个词典，存储需要进行比较的风量和风压
def selected_params(pro_datas):
    qs = {}
    delta_hs = {}
    sensor_hs_set = pro_datas['sensor_hs_set']
    sensor_qs_set = pro_datas['sensor_qs_set']
    fan_set = pro_datas['fan_set']
    struct_set = pro_datas['struct_set']
    fan_hs = {}
    st_hs = {}
    # 压差传感器，高压节点到低压节点压能（高低以绝对值区分）
    for pro_delta_h in sensor_hs_set:
        if pro_delta_h['h'] is None:
            continue
        # 节点压差
        if pro_delta_h['s'] is not None and pro_delta_h['t'] is not None:
            delta_hs['%s-%s'%(pro_delta_h['s'],pro_delta_h['t'])] = pro_delta_h['h']
        # 风机压差
        if pro_delta_h['s'] is None and pro_delta_h['t'] is not None and pro_delta_h['idFan'] is not None:
            for fan in fan_set:
                if pro_delta_h['idFan'] == fan['id']:
                    # 格式：{'末节点id-分支id':压差}
                    fan_hs['%s-%s'%(pro_delta_h['t'],fan['e_id'])] = pro_delta_h['h']
                    break
        # 构筑物压差
        if pro_delta_h['s'] is None and pro_delta_h['t'] is None and pro_delta_h['idSt'] is not None:
            for st in struct_set:
                if pro_delta_h['idSt'] == st['id']:
                    st_hs[st['e_id']] = pro_delta_h['h']
                    break
    # 风量传感器
    for pro_q in sensor_qs_set:
        qs[pro_q['e_id']] = pro_q['q']
    if len(qs) < 1 and len(delta_hs) < 1:
        return None
    return {'q':qs,'delta_h':delta_hs,'st_h':st_hs,'fan_h':fan_hs}

def vnet_cheak_test(vnet,result_dir):
    print('节点数:%d个---分支数:%d条'%(len(vnet.node_set),len(vnet.edge_set)))
    print('')
    # 进风井
    in_edges = vnet.source_edges()
    vnet.print_edge_datas_by_id(in_edges, msg = '进风井数据[%d个]'%(len(in_edges)))
    print('')
    # 回风井
    out_edges = vnet.sink_edges()
    vnet.print_edge_datas_by_id(out_edges, msg = '回风井数据[%d个]'%(len(out_edges)))
    print('')
    # 单向回路
    comps = vnet.unidir_circle()
    c_n = len(comps)
    if c_n < 1:
        print('无单向回路')
    else:
        for i,cp in enumerate(comps):
            ids_str = 'e'+'--e'.join(cp)
            vs = []
            for c in cp:
                st_ids = vnet.get_st_ids(c)
                if st_ids is None:
                    continue
                vs.extend(st_ids)
            vs = list(set(vs))
            vs_ids_str = 'v'+'->v'.join('%s'%_id for _id in vs)
            print('第%d个单向回路:%s\n(%s)'%(i+1,ids_str,vs_ids_str))
    print('')
    # 固定风量
    vnet.print_fix_q()
    print('')
    # 拓扑关系
    vnet.print_tople(result_dir)
    print('')
    # 负风量分支
    vnet.print_negative_q()

# 将观测点（传感器位置）写入到属性数据中，目前只有风量
def fault_diag_sensors_init(pro_datas,sensors,is_random = False):
    # print(sensors)
    edge_set = pro_datas['edge_set']
    if is_random:
        eids = []
        for edge in edge_set:
            eids.append(edge['id'])
        sensors = random.sample(eids, len(sensors))
    
    for edge in edge_set:
        if edge['id'] in sensors:
            edge['sensor_q_used'] = 1
        else:
            edge['sensor_q_used'] = 0
    return sensors
    # print(sensors)

def run_main(config):
    func = config['func']
    data_dir = config['data_dir']
    result_dir = config['result_dir']
    pro_file = data_dir+'property.json'
    graph_file = data_dir+'graph_data.json'
    # 通过csv建立json文件
    # pro_datas = creat_json_by_csv(data_dir,pro_file)
    # 不保存中间文件property.json
    pro_datas = creat_json_by_csv(data_dir,coding='gb2312')
    # 读取JSON属性数据
    # pro_datas = read_json_file(pro_file)
    # 初始化网络图数据
    creat_graph_json_datas(pro_datas, graph_file)
    # 准备通风网络数据
    graph_datas = read_graph_datas(graph_file)
    # 构造VNet对象
    vnet = VNet(pro_datas, graph_datas)
# 1 自然分风
    if func == 1:
        if not vnet.run_vno():
            return
        vnet_print_test(vnet,result_dir)
        # 负风量分支
        vnet.print_negative_q()
        # 固定风量
        # vnet.print_fix_q()
        vnet.save_results(result_dir)

# 2 进化算法
    if func == 2:
        # 选定用于比较的风量、风压和压能,如果不选择则sel_param = None
        sel_param = selected_params(pro_datas)

        if sel_param is not None:
            vnet.print_sensor_datas(sel_param)
        ea_config = config['ea_config']
        algo_str = ea_config['algo']
        result_dir = result_dir + algo_str
        args = {'algo':algo_str,'popsize':ea_config['popsize'],'max_generations':ea_config['max_generations'],
        'cross_rate':ea_config['cross_rate'],'mutation_rate':ea_config['mutation_rate'],'terminator':ea_config['terminator'],
        'sel_params':sel_param,'use_palla':ea_config['use_palla'],'mp_nprocs':ea_config['mp_nprocs'],'use_observe_file':ea_config['use_observe_file'],
        'minimum_fitness':ea_config['minimum_fitness'], 'result_dir':result_dir + '/tmp/'}
        if not vnet.run_ea(args,use_sensors = ea_config['use_sensors']):
            print('求解失败...')
            return
        # if not vnet.run_ea(args,use_sensors = True):
        #     return
        vnet.save_results(result_dir)
        # 分支节点数据打印
        vnet_print_test(vnet,result_dir)
        # 负风量分支
        # vnet.print_negative_q()

# 3 利用给定的delta_r进行网络解算
    if func == 3:
        if vnet.run_vno_delta_r(config['dot_dir']):
            vnet_print_test(vnet,result_dir)
            # vnet.save_results(result_dir)
# 4 网络检查测试
    if func == 4:
        vnet_cheak_test(vnet,result_dir)

# **************************arg参数说明*********************************#
# func = 1 自然分风,此时的r=r0，无论给定的delta_r是否为非0,q0等初始参数不变 
# func = 2 遗传算法 其中sel_param表示q0,h0不为零的情况需要被考虑，
#         即在适应值计算时进行比较，若将所有的风量、风压都选定作为
#         比较，则给定(在run_main函数中)sel_param = None
#         为了比较结果，此时输出的q0为r=r0时的风量，风压对应一样,
#         q为最优解delta_r+r0计算的结果
#         而选定的参数在打印出来的“选定比较参数”中显示
# func = 3 利用给定的delta_r进行网络解算,此时计算的风阻 r = r0+delta_r
# func = 4 网络检查测试 包括分支数、节点数、进回风井、拓扑关系、单向回路及负风量
# use_palla 是否使用并行,mp_nprocs cpu使用核数
# **************************arg参数说明*********************************#

if __name__ == "__main__":
    config = read_json_file('./datas/config.json')
    run_main(config)
